﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OverStore.Configuration;
using System.Data.SqlServerCe;
using OverStore.Runtime.OverStoreContext;
using OverStore.Runtime.Storage;
using OverStore.Runtime;
using OverStore.Configuration.Storage;
using OverStore.Configuration.Components;
using System.Reflection;
using OverStore.Scoping;
using OverStore.Scoping.Manager;
using OverStore.Runtime.ObjectRepository;
using OverStore.Runtime.ObjectRepository.Mapping;
using OverStore.Configuration.ObjectRepository;
using OverStore.Configuration.ObjectRepository.CommandSet;
using OverStore.Configuration.ObjectRepository.Reader;

namespace OverStore.TutorialAsTest.UnitTest.Runtime
{
    /// <summary>
    /// Summary description for ReloadCollection
    /// </summary>
    [TestClass]
    public class ReloadCollection_Test
    {
        private class NamedItemDataStorageMock : IDataStorage, IComponentConfiguration<IDataStorage>
        {
            private readonly OperationScopeManager _ScopeManager = new OperationScopeManager();
            public IDataStorage CreateComponent(IOverStoreContext context)
            {
                return new NamedItemDataStorageMock();
            }

            public TypedRecord Execute(ICommand command, IRecord parameters, out int rowsAffected)
            {
                var c = (NamedItemCommandMock)command;
                return c.ExecuteRead(parameters, out rowsAffected);
            }

            public IEnumerable<TypedRecord> ReadAll(ICommand command, IRecord parameters)
            {
                var c = (NamedItemCommandMock)command;
                return c.ExecuteReader(parameters);
            }

            public bool Disposed { get { return false; } }

            public OperationScope OpenScope()
            {
                var r = new OperationScope();
                _ScopeManager.StartOperationScope(r);
                return r;
            }

            public OverStore.Sql.SqlFormatting SqlFormatting
            {
                get { throw new NotImplementedException(); }
            }
        }

        private class NamedItemCommandMock : ICommand, IComponentConfiguration<ICommand>
        {
            private static List<DictionaryTypedRecord> Items = new List<DictionaryTypedRecord>();

            static NamedItemCommandMock()
            {
                Items.Add(new DictionaryTypedRecord(
                                    new KeyValuePair<string, object>("ID", new Guid("2A4C2062-CBA7-4fa6-963A-A50DA0557DFE")),
                                    new KeyValuePair<string, object>("Name", "Item 1")));
                Items.Add(
                    new DictionaryTypedRecord(
                                    new KeyValuePair<string, object>("ID", new Guid("BBBC2062-CBA7-4fa6-963A-A50DA0557DFE")),
                                    new KeyValuePair<string, object>("Name", "Second Item")));


            }

            #region ICommand Members

            public IRecord ExecuteCommand(IRecord parameters, out int rowsAffected)
            {
                throw new NotSupportedException();
            }

            public TypedRecord ExecuteRead(IRecord parameters, out int rowsAffected)
            {
                Guid id = (Guid)parameters.GetValue("ID");
                var result = Items.Where(record => (Guid)record.GetValue("ID") == id).FirstOrDefault();
                rowsAffected = result == null ? 0 : 1;
                return result;
            }

            public IEnumerable<TypedRecord> ExecuteReader(IRecord parameters)
            {
                foreach (var item in Items)
                    yield return item;
            }

            public TypedRecord ExecuteWrite(IRecord parameters, out int rowsAffected)
            {
                throw new NotSupportedException();
            }

            #endregion

            #region ICommandConfiguration Members

            public ICommand CreateComponent(IOverStoreContext context)
            {
                return this;
            }

            #endregion
        }

        static IComponentConfiguration<IMapper<NamedItem>> CreateNamedItemMapper()
        {
            return Component.Mapper.Delegate<NamedItem>(
                (item, name, p) =>
                {
                    if (name == "ID")
                        return item.ID;
                    if (name == "Name")
                        return item.Name;
                    if (name == "orig__oid")
                        return p.GetIdentifier<NamedItem, Guid>(item);
                    return Missing.Value;
                },
                (data, item, p) =>
                {
                    item.Name = data.GetString("Name");
                });
        }

        private IComponentConfiguration<IRepository<NamedItem>> CreateRepositoryConfig()
        {
            return new PersistenceObjectRepositoryConfiguration<NamedItem, Guid>
            {
                ChangesTracker = Component.InstanceChangesTracker.Checksum<NamedItem, Guid>("Id", "Name"),
                Commands = new CommandSetConfiguration
                                {
                                    SelectCommand = new NamedItemCommandMock()
                                },
                Depot = Component.Depot.WithInternalKey<NamedItem, Guid>("ID"),
                Mapper = CreateNamedItemMapper(),
                ParameterlessReader = new ParameterlessReaderConfiguration<NamedItem, Guid>
                {
                    IdentifierProvider = Component.IdentifierProvider.Delegate<Guid>(r => r.GetGuid("ID")),
                    ReadCommand = new NamedItemCommandMock()
                }
            };
        }

        private OverStoreConfiguration CreateConfig()
        {
            return new OverStoreConfiguration()
            {
                Logger = Component.Logger.Dummy(),
                DataStorage = new NamedItemDataStorageMock(),
                Repositories = new List<IComponentConfiguration<IRepositoryBase>> { (IComponentConfiguration<IRepositoryBase>)CreateRepositoryConfig() },
            };
        }

        [TestMethod]
        public void ReloadCollection_InstanceReferenceEquality()
        {
            var config = CreateConfig();
            using (var session = (OverStorePersistenceSession)config.CreateSession())
            using (var session1 = (OverStorePersistenceSession)config.CreateSession())
            {
                var origin = session.CreateReader<NamedItem>().First();
                var item1 = session1.CreateReader<NamedItem>().First();
                Assert.AreNotSame(origin, item1);
            }
        }

    }
}
